package com.zzc.legou.search.service;

import com.zzc.legou.item.entity.Brand;
import com.zzc.legou.item.entity.Category;
import com.zzc.legou.item.entity.SpecParam;
import com.zzc.legou.search.clients.BrandClient;
import com.zzc.legou.search.clients.CategoryClient;
import com.zzc.legou.search.clients.SpecParamClient;
import com.zzc.legou.search.dao.GoodsDao;
import com.zzc.legou.search.entity.Goods;
import com.zzc.legou.search.vo.SearchRequest;
import com.zzc.legou.search.vo.SearchResult;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.*;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.*;
import org.springframework.data.elasticsearch.core.query.*;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class SearchService {
    @Autowired
    private GoodsDao goodsDao;

    @Autowired
    private ElasticsearchRestTemplate restTemplate;

    @Autowired
    private BrandClient brandClient;

    @Autowired
    private CategoryClient categoryClient;

    @Autowired
    private SpecParamClient specParamClient;

    /**
     * 海量信息搜索
     *
     * @param request
     * @return
     */
    public SearchResult searchQuery(SearchRequest request) {
        //通用条件封装使用
        NativeSearchQueryBuilder queryBuilder = getNativeSearchQueryBuilder(request);

        //进行商品的获取
        List<Brand> bandList = getBandList(queryBuilder);

        //进行品牌获取
        List<Category> cateoryList = getCateoryList(queryBuilder);

        //分页查询
        SearchPage<Goods> searchHits = getPage(request, queryBuilder);
        long totalElements = searchHits.getTotalElements();
        long totalPages = searchHits.getTotalPages();

        //获取item信息
        List<Goods> collect = getGoods(searchHits);
        List<Map<String, Object>> specsInfo = getSpecsInfo(queryBuilder, cateoryList);

        SearchResult searchResult = new SearchResult(totalElements, totalPages, collect, cateoryList, bandList, specsInfo);
        return searchResult;
    }

    /**
     * 获取specs信息
     *
     * @param queryBuilder 构造条件
     * @param cateoryList  所需商品的信息
     * @return
     */
    private List<Map<String, Object>> getSpecsInfo(NativeSearchQueryBuilder queryBuilder, List<Category> cateoryList) {
        //获取specs信息
        List<Map<String, Object>> specs = new ArrayList<>();
        //只有搜索对应的分类个数是1的时候才能聚合规格参数
        //根据用户的搜索条件对应的产品分类查询产品对应的规格参数
        if (cateoryList.size() == 1) {
            Long cid = cateoryList.get(0).getId();
            SpecParam specParam = new SpecParam();
            specParam.setCid(cid);
            specParam.setSearching(true);
            List<SpecParam> specParams = specParamClient.selectSpecParamApi(specParam);
            //添加查询条件
            for (SpecParam specParam1 : specParams) {
                String name = specParam1.getName();
                queryBuilder.addAggregation(AggregationBuilders.terms(name).field("specs." + name + ".keyword"));
            }
            SearchHits<Goods> search = restTemplate.search(queryBuilder.build(), Goods.class);
            Aggregations aggregations = search.getAggregations();
            //遍历获取数据进行封装操作
            Map<String, Aggregation> asMap = aggregations.getAsMap();
            for (SpecParam param : specParams) {
                Map<String, Object> map = new HashMap<>();
                String name = param.getName();
                ParsedStringTerms terms = (ParsedStringTerms) asMap.get(name);
                List<? extends Terms.Bucket> buckets = terms.getBuckets();
                //存放数据值
                ArrayList<String> strings = new ArrayList<>();
                for (Terms.Bucket bucket : buckets) {
                    String keyAsString = bucket.getKeyAsString();
                    strings.add(keyAsString);
                }
                map.put("k", name);
                map.put("options", strings);
                specs.add(map);
            }
        }
        return specs;
    }

    /**
     * 获取Specs信息
     *
     * @return
     */
    private List<Map<String, Object>> getSpecs() {
        List<Map<String, Object>> maps = new ArrayList<>();
        return maps;
    }

    /**
     * item获取信息
     *
     * @param searchHits
     * @return
     */
    private List<Goods> getGoods(SearchPage<Goods> searchHits) {
        List<SearchHit<Goods>> content = searchHits.getContent();
        return searchHits.get().map(item -> item.getContent()).collect(Collectors.toList());
    }

    /**
     * 通用查询条件封装使用
     *
     * @param request
     * @return
     */
    private NativeSearchQueryBuilder getNativeSearchQueryBuilder(SearchRequest request) {
        //查询条件
        String key = request.getKey();
        //查询字段
        String sortBy = request.getSortBy();
        //判断升序还是降序
        Boolean descending = request.getDescending();
        //构建本地的查询条件
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //构建bool查询器
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //封装 排序字段
        if (!StringUtils.isEmpty(sortBy)) {
            queryBuilder.withSort(SortBuilders.fieldSort(sortBy).order(descending ? SortOrder.DESC : SortOrder.ASC));
        }
        //查询所有的信息
        boolQueryBuilder.must(QueryBuilders.matchQuery("all", key));
        queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{"id", "skus", "subTitle"}, null)).withQuery(boolQueryBuilder);
        queryBuilder.addAggregation(AggregationBuilders.terms("brands").field("brandId"));
        queryBuilder.addAggregation(AggregationBuilders.terms("categories").field("cid3"));
        return queryBuilder;
    }

    /**
     * 获取品牌信息
     *
     * @param queryBuilder
     */
    private List<Brand> getBandList(NativeSearchQueryBuilder queryBuilder) {
        List<Long> brands = getListLong(queryBuilder, "brands");
        //远程调用查询bandid所数的类别
        List<Brand> brands1 = brandClient.selectBrandByIds(brands);
        return brands1;
    }

    /**
     * 获取category信息
     *
     * @param queryBuilder
     */
    private List<Category> getCateoryList(NativeSearchQueryBuilder queryBuilder) {

        List<Long> categoryids = getListLong(queryBuilder, "categories");
        System.out.println("categoryids = " + categoryids);
        //远程调用查询bandid所数的类别
        List<String> names = categoryClient.queryNameByIds(categoryids);
        System.out.println("names = " + names);
        List<Category> categoryList = new ArrayList<>();
        for (int i = 0; i < names.size(); i++) {
            Category category = new Category();
            category.setId(categoryids.get(i));
            category.setTitle(names.get(i));
            categoryList.add(category);
        }
        return categoryList;
    }

    /**
     * 获取所需参数的id信息
     *
     * @param queryBuilder 构造条件
     * @param param        参数信息
     * @return
     */
    private List<Long> getListLong(NativeSearchQueryBuilder queryBuilder, String param) {
        SearchHits<Goods> search = restTemplate.search(queryBuilder.build(), Goods.class);
        Aggregations aggregations = search.getAggregations();
        Map<String, Aggregation> asMap = aggregations.getAsMap();
        ParsedLongTerms longTerms = (ParsedLongTerms) asMap.get(param);
        List<? extends Terms.Bucket> buckets = longTerms.getBuckets();
        List<Long> longList = new ArrayList<>();
        for (Terms.Bucket bucket : buckets) {
            longList.add(bucket.getKeyAsNumber().longValue());
        }
        return longList;
    }


    /**
     * 获取分页信息
     *
     * @param request      请求参数
     * @param queryBuilder 构造请求语句
     * @return
     */
    private SearchPage<Goods> getPage(SearchRequest request, NativeSearchQueryBuilder queryBuilder) {
        PageRequest pageRequest = PageRequest.of(request.getPage(), request.getSize());
        SearchHits<Goods> goodsSearchHits = restTemplate.search(queryBuilder.build(), Goods.class);
        return SearchHitSupport.searchPageFor(goodsSearchHits, pageRequest);
    }


}
